<?php

namespace App\V3\Api\Services;

use App\V3\Api\Models\LogInStorageModel;
use App\V3\Api\Models\LogOutStorageModel;
use App\V3\Api\Models\LogPackageModel;
use App\V3\Api\Models\SerialNumberModel;
use App\V3\Api\Models\StorageBatchModel;
use App\V3\Api\Models\StorageManageModel;
use \Exception;
use Illuminate\Support\Facades\DB;
use App\V3\Api\Models\MaterielSerialNumberModel;
use Illuminate\Support\Facades\Log;

class LogService
{
    //操作记录详细
    static public function detail($data)
    {
        switch($data['type']) {
            case 0:
                $result = SELF::logInstorageDetail($data);
                break;
            case 1:
                $result = SELF::logOutstorageDetail($data);
                break;
            case 2:
                $result = SELF::logPackageContentDetail($data);
                break;
        }

        /* if(!empty($result['is_use_serial'])){

            if($result['is_use_serial'] == 1){
                $condition['type_id']=$result['type_id'];
                $condition['materiel_content_id']=$result['id'];

                $info = MaterielSerialNumberModel::select('serial_no')->where($condition)->first();

                $result['serial_number_list']=[];

                if(!empty($info['serial_no'])){

                    $result['serial_number_list'] = explode(',', $info['serial_no']);
                }
            }
        }

        if(!empty($result['content']['is_use_serial'])){

            if($result['content']['is_use_serial'] == 1){
                MaterielSerialNumberModel::where()->first();
            }
        } */

        return $result;

    }

    static private function logInstorageDetail($data)
    {
        $info = LogInstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name as last_storage_name',
            'f.storage_address as last_storage_address',
            'e.storage_name',
            'e.storage_address',
//            'a.materiel_class_name',
//            'a.materiel_class_no',
            'g.materiel_name',
            'g.type_name',
            'g.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.all_id_type',
            'a.remark',
            'a.is_cancel',
            'a.in_storage_time',
            'a.purchase_no',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',
            'c.class_name',
            'c.class_no',
            'd.username',
            'd.nickname',
            'g.is_use_serial',
            'serial_number',
            'i.batch_no'
        )
            ->from('log_instorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('storage as e', 'e.id', '=', 'a.storage_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.last_storage_id')
            ->leftJoin('materiel_type as g', 'g.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage_batch as i','i.id','=','a.batch_id')
            ->where([
                'a.id' => $data['id'],
            ])
            ->first();

            if(!empty($info['serial_number'])){
                $info['serial_number'] = explode(',', $info['serial_number']);
            }else{
                $info['serial_number'] = [];
            }
            return $info;
    }

    //出库操作记录详细
    static private function logOutstorageDetail($data)
    {
         $info = LogOutstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name as next_storage_name',
            'f.storage_address as next_storage_address',
            'e.storage_name',
            'e.storage_address',
//                'a.materiel_class_name',
//                'a.materiel_class_no',
            'g.materiel_name',
            'g.type_name',
            'g.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.all_id_type',
            'a.is_cancel',
            'a.out_storage_time',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',
            'c.class_name',
            'c.class_no',
            'd.username',
            'd.nickname',
            'g.is_use_serial',
            'a.serial_number',
            'i.batch_no'
        )
            ->from('log_outstorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('storage as e', 'e.id', '=', 'a.storage_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.next_storage_id')
            ->leftJoin('materiel_type as g', 'g.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage_batch as i','i.id','=','a.storage_batch_id')
            ->where([
                'a.id' => $data['id']
            ])
            ->first();

            if(!empty($info['serial_number'])){
                $info['serial_number'] = explode(',', $info['serial_number']);
            }else{
                $info['serial_number'] = [];
            }

            return $info;
    }

    //套餐出库记录详细
    static public function logPackageContentDetail($data)
    {
        $datas = LogPackageModel::select(
            'a.id',
            'c.package_name',
            'num',
            'remark',
            'a.created_at',
            'username',
            'nickname',
            'is_cancel',
            'a.remark'
        )
            ->from('log_package as a')
            ->leftJoin('admin as b', 'b.id', '=', 'a.user_id')
            ->with('hasManyContent', function($query) {
                $query->select(
                    'log_package_content.id',
                    'log_package_id',
                    'a.storage_name',
                    'a.storage_address',
                    'b.class_name as second_class_name',
                    'c.class_name as first_class_name',
                    'd.materiel_name',
                    'd.type_name',
                    'operate_num',
                    'e.in_storage_num',
                    'd.is_use_serial',
                    'log_package_content.serial_number',
                    'i.batch_no'
                )
                    ->leftJoin('storage as a', 'a.id', '=', 'log_package_content.storage_id')
                    ->leftJoin('materiel_class as b', 'b.id', '=', 'log_package_content.materiel_class_id')
                    ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
                    ->leftJoin('materiel_type as d', 'd.id', '=', 'log_package_content.materiel_type_id')
                    ->leftJoin('storage_manage as e', 'e.id', '=', 'log_package_content.out_storage_manage_id')
                    ->leftJoin('storage_batch as i','i.id','=','log_package_content.storage_batch_id');
            })
            ->leftJoin('package as c', 'c.id', '=', 'a.package_id')
            ->where('a.id', $data['id'])
            ->get()->toArray();
            if(!empty($datas[0]['has_many_content'])){
                foreach ($datas[0]['has_many_content'] as &$v){
                    if(!empty($v['serial_number'])){
                        $v['serial_number'] = explode(',', $v['serial_number']);
                    }else{
                        $v['serial_number']=[];
                    }
                }
            }
        $arr['id'] = $datas[0]['id'];
        $arr['package_name'] = $datas[0]['package_name'];
        $arr['num'] = $datas[0]['num'];
        $arr['remark'] = $datas[0]['remark'];
        $arr['created_at'] = $datas[0]['created_at'];
        $arr['username'] = $datas[0]['username'];
        $arr['nickname'] = $datas[0]['nickname'];
        $arr['is_cancel'] = $datas[0]['is_cancel'];
        $arr['content'] = $datas[0]['has_many_content'];

        return $arr;
    }


    static public function logDel($data, $logIdArr, $condition)
    {
        switch($data['type']) {
            //入库
            case 0:
                $result = SELF::instorageDel($logIdArr, $condition);
                break;
            //出库
            case 1:
                $result = SELF::outstorageDel($logIdArr, $condition);
                break;
            //套餐出库
            case 2:
                $result = SELF::packageOutstorageDel($logIdArr, $condition);
                break;
        }

        return $result;
    }

    static private function instorageDel($logIdArr, $condition)
    {

        foreach($logIdArr as $value) {
            $logInfo = LogInstorageModel::where([
                'id' => $value,
                'delete_flag' => 0
            ])
                ->where($condition)
                ->first();

            if(empty($logInfo)) {
                return ['code' => 1, 'msg' => '目标日志不存在,请重试', 'data' => ''];
            }

            if(!$logInfo['is_cancel']) {
                return ['code' => 1, 'msg' => '目标日志未撤销，不可删除', 'data' => ''];
            }
        }

        LogInstorageModel::whereIn('id', $logIdArr)->update(['delete_flag' => 1]);

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    static private function outstorageDel($logIdArr, $condition)
    {
        foreach($logIdArr as $value) {
            $logInfo = LogOutstorageModel::where([
                'id' => $value,
                'delete_flag' => 0
            ])
                ->where($condition)
                ->first();

            if(empty($logInfo)) {
                return ['code' => 1, 'msg' => '目标日志不存在,请重试', 'data' => ''];
            }

            if(!$logInfo['is_cancel']) {
                return ['code' => 1, 'msg' => '目标日志未撤销，不可删除', 'data' => ''];
            }
        }

        LogOutstorageModel::whereIn('id', $logIdArr)->update(['delete_flag' => 1]);

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }

    static private function packageOutstorageDel($logIdArr, $condition)
    {
        foreach($logIdArr as $value) {
            $logInfo = LogPackageModel::where([
                'id' => $value,
                'delete_flag' => 0
            ])
                ->where($condition)
                ->first();

            if(empty($logInfo)) {
                return ['code' => 1, 'msg' => '目标日志不存在,请重试', 'data' => ''];
            }

            if(!$logInfo['is_cancel']) {
                return ['code' => 1, 'msg' => '目标日志未撤销，不可删除', 'data' => ''];
            }
        }

        LogPackageModel::whereIn('id', $logIdArr)->update(['delete_flag' => 1]);

        return ['code' => 0, 'msg' => 'success', 'data' => ''];
    }


    //操作记录列表
    static public function list($data, $status, $userId)
    {
        //DB::enableQueryLog();
        switch($data['type']) {
            //入库
            case 0:
                $result = SELF::instorageList($data, $status, $userId);
                break;
                //出库
            case 1:
                $result = SELF::outstorageList($data, $status, $userId);
                break;
                //套餐出库
            case 2:
                $result = SELF::packageOutstorageList($data, $status, $userId);
                break;
        }
        // $sql = DB::getQueryLog();
        //var_dump($sql);die;
        return $result;
    }

    //入库操作记录
    static private function instorageList($data, $status, $userId)
    {
        $query = LogInstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name',
            'f.storage_address',
            'g.storage_name as last_storage_name',
            'g.storage_address as last_storage_address',
            //            'a.materiel_class_name',
        //            'a.materiel_class_no',
            'e.materiel_name',
            'e.type_name',
            'e.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.is_cancel',
            'a.in_storage_time',
            'a.purchase_no',
            'c.class_name',
            'c.class_no',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',
            'd.username',
            'd.nickname',
            'h.location_name',
            'i.shelf_name',
            'a.serial_number'
            )
            ->from('log_instorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.storage_id')
            ->leftJoin('storage as g', 'g.id', '=', 'a.last_storage_id')
            ->leftJoin('storage_shelf_location as h','h.id','=','a.location_id')
            ->leftJoin('storage_shelf as i','i.id','=','a.shelf_id')
            ->where('a.delete_flag', 0)
            ->where($userId)
            ->where('a.is_cancel', $status);

            if($data['materiel_class_id'] != 0) {
                $query->where('a.materiel_class_id', $data['materiel_class_id']);
            }

            $keyword = empty($data['keyword'])?'':$data['keyword'];

            if(!empty($data['start_time'])) {
                $startTimeArr = explode(' ', $data['start_time']);
                $startTime = strtotime($startTimeArr[0].' 00:00:00');
            }

            if(!empty($data['end_time'])) {
                $endTimeArr = explode(' ', $data['end_time']);
                $endTime = strtotime($endTimeArr[0].' 23:59:59');
            }

            if(!empty($startTime) && !empty($endTime)) {
                $query->whereBetween('in_storage_time', [$startTime, $endTime]);
            }
            else if(!empty($startTime) && empty($endTime)) {
                $query->where('in_storage_time', '>=', $startTime);
            }
            else if(empty($startTime) && !empty($endTime)) {
                $query->where('in_storage_time', '<=', $endTime);
            }

            return $query->where(function($query) use ($keyword, $data) {
                $query->orWhere('b.class_name', 'like', '%'.$keyword.'%');
                $query->orWhere('b.class_no', 'like', '%'.$keyword.'%');
                $query->orWhere('c.class_name', 'like', '%'.$keyword.'%');
                $query->orWhere('c.class_no', 'like', '%'.$keyword.'%');
                $query->orWhere('e.materiel_name', 'like', '%'.$keyword.'%');
                $query->orWhere('e.type_name', 'like', '%'.$keyword.'%');
                $query->orWhere('e.materiel_no', 'like', '%'.$keyword.'%');
                $query->orWhere('f.storage_name', 'like', '%'.$keyword.'%');
                $query->orWhere('g.storage_name', 'like', '%'.$keyword.'%');

                if($data['type'] == 0) {
                    $query->orWhere('purchase_no', 'like', '%'.$keyword.'%');
                }
            })
            ->orderBy('a.id', 'desc')
            ->paginate($data['pageSize'],['*'], '',$data['currentPage'])->toArray();
    }

    //出库操作记录
    static private function outstorageList($data, $status, $userId)
    {
        $query = LogOutstorageModel::select(
            'a.id',
            'a.type',
            'f.storage_name',
            'f.storage_address',
            'g.storage_name as next_storage_name',
            'g.storage_address as next_storage_address',
            //            'a.materiel_class_name',
        //            'a.materiel_class_no',
            'e.materiel_name',
            'e.type_name',
            'e.materiel_no',
            'a.operate_num',
            'a.last_storage_num',
            'a.next_storage_num',
            'a.materiel_mean_cost',
            'a.remark',
            'a.is_cancel',
            'a.out_storage_time',
            'c.class_name',
            'c.class_no',
            'b.class_name as materiel_class_name',
            'b.class_no as materiel_class_no',
            'd.username',
            'd.nickname',
            'h.location_name',
            'i.shelf_name',
            'a.serial_number'
            )
            ->from('log_outstorage as a')
            ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
            ->leftJoin('materiel_class as c', 'b.parent_id', '=', 'c.id')
            ->leftJoin('admin as d', 'd.id', '=', 'a.user_id')
            ->leftJoin('materiel_type as e', 'e.id', '=', 'a.materiel_type_id')
            ->leftJoin('storage as f', 'f.id', '=', 'a.storage_id')
            ->leftJoin('storage as g', 'g.id', '=', 'a.next_storage_id')
            ->leftJoin('storage_shelf_location as h','h.id','=','a.location_id')
            ->leftJoin('storage_shelf as i','i.id','=','a.shelf_id')
            ->where('a.delete_flag', 0)
            ->where($userId)
            ->where('is_cancel', $status);

            if($data['materiel_class_id'] != 0) {
                $query->where('a.materiel_class_id', $data['materiel_class_id']);
            }

            $keyword = empty($data['keyword'])?'':$data['keyword'];

            if(!empty($data['start_time'])) {
                $startTimeArr = explode(' ', $data['start_time']);
                $startTime = strtotime($startTimeArr[0].' 00:00:00');
            }

            if(!empty($data['end_time'])) {
                $endTimeArr = explode(' ', $data['end_time']);
                $endTime = strtotime($endTimeArr[0].' 23:59:59');
            }

            if(!empty($startTime) && !empty($endTime)) {
                $query->whereBetween('out_storage_time', [$startTime, $endTime]);
            }
            else if(!empty($startTime) && empty($endTime)) {
                $query->where('out_storage_time', '>=', $startTime);
            }
            else if(empty($startTime) && !empty($endTime)) {
                $query->where('out_storage_time', '<=', $endTime);
            }

            return $query->where(function($query) use ($keyword, $data) {
                $query->orWhere('b.class_name', 'like', '%'.$keyword.'%');
                $query->orWhere('b.class_no', 'like', '%'.$keyword.'%');
                $query->orWhere('c.class_name', 'like', '%'.$keyword.'%');
                $query->orWhere('c.class_no', 'like', '%'.$keyword.'%');
                $query->orWhere('e.materiel_name', 'like', '%'.$keyword.'%');
                $query->orWhere('e.type_name', 'like', '%'.$keyword.'%');
                $query->orWhere('e.materiel_no', 'like', '%'.$keyword.'%');
                $query->orWhere('f.storage_name', 'like', '%'.$keyword.'%');
                $query->orWhere('g.storage_name', 'like', '%'.$keyword.'%');

                if($data['type'] == 0) {
                    $query->orWhere('purchase_no', 'like', '%'.$keyword.'%');
                }
            })
            ->orderBy('a.id', 'desc')
            ->paginate($data['pageSize'],['*'], '',$data['currentPage'])->toArray();
    }

    static public function packageOutstorageList($data, $status, $userId)
    {
        $keyword = empty($data['keyword'])?'':$data['keyword'];

        $query = LogPackageModel::select(
            'a.id',
            'a.package_name',
            'a.num',
            'a.remark',
            'a.is_cancel',
            'a.created_at',
            'username',
            'nickname',
            'd.location_name',
            'e.shelf_name',
            'c.serial_number'
            )
            ->from('log_package as a')
            ->leftJoin('admin as b', 'b.id', '=', 'a.user_id')
            ->leftJoin('log_package_content as c', 'c.log_package_id', '=', 'a.id')
            ->leftJoin('storage_shelf_location as d','d.id','=','c.location_id')
            ->leftJoin('storage_shelf as e','e.id','=','c.shelf_id')
            ->where('a.delete_flag', 0)
            ->where($userId)
            ->where('a.is_cancel', $status);

            if(!empty($data['start_time'])) {
                $startTimeArr = explode(' ', $data['start_time']);
                $startTime = strtotime($startTimeArr[0].' 00:00:00');
            }

            if(!empty($data['end_time'])) {
                $endTimeArr = explode(' ', $data['end_time']);
                $endTime = strtotime($endTimeArr[0].' 23:59:59');
            }

            if(!empty($startTime) && !empty($endTime)) {
                $query->whereBetween('a.created_at', [$startTime, $endTime]);
            }
            else if(!empty($startTime) && empty($endTime)) {
                $query->where('a.created_at', '>=', $startTime);
            }
            else if(empty($startTime) && !empty($endTime)) {
                $query->where('a.created_at', '<=', $endTime);
            }

            $query->where(function($query) use ($keyword) {
                $query->orWhere('package_name', 'like', '%'.$keyword.'%');
                $query->orWhere('materiel_name', 'like', '%'.$keyword.'%');
                $query->orWhere('type_name', 'like', '%'.$keyword.'%');
                $query->orWhere('materiel_no', 'like', '%'.$keyword.'%');
                $query->orWhere('materiel_class_name', 'like', '%'.$keyword.'%');
                $query->orWhere('materiel_class_no', 'like', '%'.$keyword.'%');
            });

                return $query->orderBy('a.id', 'desc')
                ->groupBy('a.id')
                ->paginate($data['pageSize'],['*'], '',$data['currentPage'])->toArray();
    }

    static public function cancelAllocateOut($data)
    {
        $info = LogOutStorageModel::where('id', $data['id'])->first();

        if($info['is_cancel']) {
            return ['code' => 1, 'msg' => '当前记录已经撤销，无法重复操作', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            if(!empty($info['serial_number'])) {
                self::cancelSerialAllocateOut($info);
            }
            else {
                if(!empty($info['before_allocate_batch_id'])) {
                    self::cancelBatchAllocateOut($info);
                }
                else {
                    self::cancelNormalAllocateOut($info);
                }
            }

            $info->is_cancel = 1;
            $info->save();

            LogInStorageModel::where('id', $info['log_in_id'])
                ->update([
                    'is_cancel' => 1
                ]);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('调拨入库撤销异常:'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    static private function cancelNormalAllocateOut($info)
    {
        $outstorageInfo = StorageManageModel::where('id', $info['next_storage_manage_id'])->first();

        if($outstorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if($outstorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $outstorageInfo->in_storage_num = $outstorageInfo->in_storage_num - $info['operate_num'];
        $outstorageInfo->virtual_storage_num = $outstorageInfo->virtual_storage_num - $info['operate_num'];
        $outstorageInfo->save();

        StorageManageModel::where('id', $info['curr_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('in_storage_num + '.$info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'delete_flag' => 0
            ]);

        StorageBatchModel::where('id', $info['curr_storage_manage_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + '.$info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + '.$info['operate_num']),
            ]);
//
//        LogInStorageModel::where([
//            'type' => 1,
//            'last_storage_manage_id' => $info['curr_storage_manage_id'],
//            'curr_storage_manage_id' => $info['next_storage_address'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    static private function cancelBatchAllocateOut($info)
    {
        $outstorageInfo = StorageManageModel::where('id', $info['next_storage_manage_id'])->first();

        if($outstorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if($outstorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $outstorageInfo->in_storage_num = $outstorageInfo->in_storage_num - $info['operate_num'];
        $outstorageInfo->virtual_storage_num = $outstorageInfo->virtual_storage_num - $info['operate_num'];
        $outstorageInfo->save();

        StorageManageModel::where('id', $info['curr_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'delete_flag' => 0
            ]);

        $inBatchInfo = StorageBatchModel::where('id', $info['storage_batch_id'])->first();

        if($inBatchInfo['batch_left_num'] < $info['operate_num']) {
            throw new Exception('调拨后的批次数量不足，无法完成调拨撤销，当前剩余可撤销批次数量为:'.$inBatchInfo['batch_left_num']);
        }

        $inBatchInfo->batch_left_num = $inBatchInfo->batch_left_num - $info['operate_num'];
        $inBatchInfo->batch_num = $inBatchInfo->batch_num - $info['operate_num'];
        $inBatchInfo->save();

        StorageBatchModel::where('id', $info['before_allocate_batch_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + '.$info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + '.$info['operate_num']),
            ]);

//        LogInStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['next_storage_manage_id'],
//            'last_storage_manage_id' => $info['curr_storage_manage_id'],
//            'before_allocate_batch_id' => $info['before_allocate_batch_id'],
//            'storage_batch_id' => $info['batch_id'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    static protected function cancelSerialAllocateOut($info)
    {
        $outstorageInfo = StorageManageModel::where('id', $info['next_storage_manage_id'])->first();

        if($outstorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if($outstorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $outstorageSerialInfo = SerialNumberModel::where([
            'storage_manage_id' => $info['next_storage_manage_id'],
            'serial_no' => $info['serial_number'],
        ])->first();

        if($outstorageSerialInfo['status'] == 0) {
            throw new Exception('序列号:'.$outstorageInfo['serial_no'].'已被使用，无法撤销');
        }

        $outstorageInfo->in_storage_num = $outstorageInfo->in_storage_num - $info['operate_num'];
        $outstorageInfo->virtual_storage_num = $outstorageInfo->virtual_storage_num - $info['operate_num'];
        $outstorageInfo->save();

        $outstorageSerialInfo->storage_manage_id = $info['curr_storage_manage_id'];
        $outstorageSerialInfo->save();

        StorageManageModeL::where([
            'id' => $info['curr_storage_manage_id']
        ])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'delete_flag' => 0
            ]);

        return true;
    }

    /**
     * 调拨撤销调入侧
     * @param $data
     * 2022/9/30 17:17
     * Author: Sun Wu
     * @return array
     */
    static public function cancelAllocateIn($data)
    {
        $info = LogInStorageModel::where('id', $data['id'])->first();

        if($info['is_cancel']) {
            return ['code' => 1, 'msg' => '当前记录已经撤销，无法重复操作', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            if(!empty($info['serial_number'])) {
                self::cancelSerialAllocateIn($info);
            }
            else {
                if(!empty($info['before_allocate_batch_id'])) {
                    self::cancelBatchAllocateIn($info);
                }
                else {
                    self::cancelNormalAllocateIn($info);
                }
            }

            $info->is_cancel = 1;
            $info->save();

            LogOutStorageModel::where('id', $info['log_out_id'])
                ->update([
                    'is_cancel' => 1
                ]);

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('调拨入库撤销异常:'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    /**
     * @throws Exception
     */
    static protected function cancelNormalAllocateIn($info)
    {
        $instorageInfo = StorageManageModel::where('id', $info['curr_storage_manage_id'])->first();

        if($instorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if($instorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $instorageInfo->in_storage_num = $instorageInfo->in_storage_num - $info['operate_num'];
        $instorageInfo->virtual_storage_num = $instorageInfo->virtual_storage_num - $info['operate_num'];
        $instorageInfo->save();

        StorageManageModel::where('id', $info['last_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('in_storage_num +'.$info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num +'.$info['operate_num']),
                'delete_flag' => 0
            ]);

        StorageBatchModel::where('id', $info['before_allocate_batch_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + '.$info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + '.$info['operate_num']),
            ]);

//        LogOutStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['last_storage_manage_id'],
//            'next_storage_manage_id' => $info['curr_storage_manage_id'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    /**
     * 批次调拨撤销
     * @param $info
     * 2022/9/30 17:08
     * Author: Sun Wu
     * @return bool
     */
    static protected function cancelBatchAllocateIn($info)
    {
        $instorageInfo = StorageManageModel::where('id', $info['curr_storage_manage_id'])->first();

        if($instorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if($instorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $instorageInfo->in_storage_num = $instorageInfo->in_storage_num - $info['operate_num'];
        $instorageInfo->virtual_storage_num = $instorageInfo->virtual_storage_num - $info['operate_num'];
        $instorageInfo->save();

        StorageManageModel::where('id', $info['last_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'delete_flag' => 0
            ]);

        $inBatchInfo = StorageBatchModel::where('id', $info['batch_id'])->first();

        if($inBatchInfo['batch_left_num'] < $info['operate_num']) {
            throw new Exception('调拨后的批次数量不足，无法完成调拨撤销，当前剩余可撤销批次数量为:'.$inBatchInfo['batch_left_num']);
        }

        $inBatchInfo->batch_left_num = $inBatchInfo->batch_left_num - $info['operate_num'];
        $inBatchInfo->batch_num = $inBatchInfo->batch_num - $info['operate_num'];
        $inBatchInfo->save();

        StorageBatchModel::where('id', $info['before_allocate_batch_id'])
            ->update([
                'batch_num' => DB::raw('batch_num + '.$info['operate_num']),
                'batch_left_num' => DB::raw('batch_left_num + '.$info['operate_num']),
            ]);

//        LogOutStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['last_storage_manage_id'],
//            'next_storage_manage_id' => $info['curr_storage_manage_id'],
//            'before_allocate_batch_id' => $info['before_allocate_batch_id'],
//            'storage_batch_id' => $info['batch_id'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }

    /**
     * 序列号调入撤销
     * @param $info
     * 2022/9/30 16:07
     * Author: Sun Wu
     * @return bool
     */
    static protected function cancelSerialAllocateIn($info)
    {
        $instorageInfo = StorageManageModel::where('id', $info['curr_storage_manage_id'])->first();

        if($instorageInfo['delete_flag']) {
            throw new Exception('调入库存信息不存在，无法撤销,请查验后重试');
        }

        if($instorageInfo['in_storage_num'] < 1) {
            throw new Exception('调入后的库存数量不足，无法撤销,请查验后重试');
        }

        $instorageSerialInfo = SerialNumberModel::where([
            'storage_manage_id' => $info['curr_storage_manage_id'],
            'serial_no' => $info['serial_number'],
        ])->first();

        if($instorageSerialInfo['status'] == 0) {
            throw new Exception('序列号:'.$instorageSerialInfo['serial_no'].'已被使用，无法撤销');
        }

        $instorageInfo->in_storage_num = $instorageInfo->in_storage_num - $info['operate_num'];
        $instorageInfo->virtual_storage_num = $instorageInfo->virtual_storage_num - $info['operate_num'];
        $instorageInfo->save();

        $instorageSerialInfo->storage_manage_id = $info['last_storage_manage_id'];
        $instorageSerialInfo->save();

        StorageManageModel::where('id', $info['last_storage_manage_id'])
            ->update([
                'in_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'virtual_storage_num' => DB::raw('virtual_storage_num + '.$info['operate_num']),
                'delete_flag' => 0
            ]);

        $inBatchInfo = StorageBatchModel::where('id', $info['batch_id'])->first();

        if(!empty($inBatchInfo)) {
            //撤销调入产生的批次信息
            if($inBatchInfo['batch_left_num'] > 0) {
                $inBatchInfo->batch_left_num = $inBatchInfo->batch_left_num - $info['operate_num'];
                $inBatchInfo->save();
            }
            else {
                //调入产生的批次信息数量不足，找到批次数量最大的批次抵扣一次
                $findInbatchInfo = StorageBatchModel::where('storage_manage_id', $info['curr_storage_manage_id'])
                    ->orderBy('batch_left_num', 'desc')
                    ->first();

                if($findInbatchInfo['batch_left_num'] > 0) {
                    $findInbatchInfo->batch_num = $findInbatchInfo->batch_num - $info['operate_num'];
                    $findInbatchInfo->batch_left_num = $findInbatchInfo->batch_left_num - $info['operate_num'];
                    $findInbatchInfo->save();
                }
                else {
                    //以上条件未满足时，将调入的批次删除
                    $inBatchInfo->delete_flag = 1;
                    $inBatchInfo->save();
                }
            }
        }
//
//        LogOutStorageModel::where([
//            'type' => 1,
//            'curr_storage_manage_id' => $info['last_storage_manage_id'],
//            'next_storage_manage_id' => $info['curr_storage_manage_id'],
//            'serial_number' => $info['serial_number'],
//            'allocate_no' => $info['allocate_no'],
//        ])->update(['is_cancel' => 1]);

        return true;
    }
}
